﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameLib;
using System.Windows.Media;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using Sandbox.ContentTypes;
using Sandbox.Names;
using System.Windows.Controls;
using GameLib.Utils;
using System.Collections.ObjectModel;
using Sandbox.Utils;
using CanonicalSplineLib;
using System.Windows.Media.Effects;
using GameLib.WorldMap;

namespace Sandbox.Scene.Elements
{
	public class RiverSceneObject : MapSceneObject
	{
		public RiverSceneObject(River river)
		{
			River = river;
			river.Extended += new EventHandler<RiverExtendedEventArgs>(River_Extended);

			m_RiverPathData = river.Content.Get<PathData>(ContentNames.RiverPathData);

			if (m_RiverPathData == null)
			{
				CreateNewRiverPathData();
			}

/*
			int hw = HexWidth * 3 / 4;
			int hh = HexHeight / 2;
			int hs = HexWidth / 2;

			PathFigure pathFigure = new PathFigure();
			pathFigure.StartPoint = new Point(hw * 2, hh * 3);

			BezierSegment seg1 = new BezierSegment();
			seg1.Point1 = new Point(hw * 2, hh * 3);
			seg1.Point2 = new Point(hw * 2 + hs / 2, hh * 4 + 20);
			seg1.Point3 = new Point(hw * 3, hh * 4);
			pathFigure.Segments.Add(seg1);

			BezierSegment seg2 = new BezierSegment();
			seg2.Point1 = new Point(hw * 3 + hs / 2, hh * 5);
			seg2.Point2 = new Point(hw * 4, hh * 5);
			seg2.Point3 = new Point(hw * 6, hh * 7);
			pathFigure.Segments.Add(seg2);

			PathGeometry pathGeo = new PathGeometry();
			pathGeo.Figures.Add(pathFigure);*/

			PathGeometry pathGeo = CreatePathGeo();
			
			m_RiverPathContour = new Path();
			BlurEffect effect = new BlurEffect();
			effect.Radius = 5;
			m_RiverPathContour.Opacity = 0.7;
			m_RiverPathContour.Effect = effect;
			m_RiverPathContour.Stroke = new SolidColorBrush(Colors.LightBlue);
			m_RiverPathContour.StrokeThickness = 16;
			m_RiverPathContour.Data = pathGeo;
			Canvas.SetZIndex(m_RiverPathContour, 1);

			
			/*
			m_RiverPathContour = new Path();
			m_RiverPathContour.Stroke = new SolidColorBrush(Colors.DarkBlue);
			m_RiverPathContour.StrokeThickness = 10;
			m_RiverPathContour.RenderTransform = new TranslateTransform(-2, -2);
			m_RiverPathContour.Opacity = 1;
			m_RiverPathContour.Data = pathGeo;
			Canvas.SetZIndex(m_RiverPathContour, 1);

			m_RiverPathContour2 = new Path();
			m_RiverPathContour2.Stroke = new SolidColorBrush(Colors.LightBlue);
			m_RiverPathContour2.RenderTransform = new TranslateTransform(2, 2);
			m_RiverPathContour2.StrokeThickness = 10;
			m_RiverPathContour2.Opacity = 1;
			m_RiverPathContour2.Data = pathGeo;
			Canvas.SetZIndex(m_RiverPathContour2, 2);*/
			
			m_RiverPathWater = new Path();
			TileBrush riverTile = new ImageBrush(new BitmapImage(new Uri("Content/Images/Map/Elements/water dark_hi.png", UriKind.Relative)));
			riverTile.ViewportUnits = BrushMappingMode.Absolute;
			riverTile.Viewport = new Rect(0, 0, 200, 200);
			riverTile.TileMode = TileMode.Tile;

			m_RiverPathWater.Stroke = riverTile; //  new SolidColorBrush(Colors.DeepSkyBlue);
			m_RiverPathWater.StrokeThickness = 10;
			m_RiverPathWater.Data = pathGeo;
			Canvas.SetZIndex(m_RiverPathWater, 5);
		}

		public River River
		{
			get;
			private set;
		}

		protected override void Display()
		{
			SceneCanvas.Children.Add(m_RiverPathContour);
			//SceneCanvas.Children.Add(m_RiverPathContour2);
			SceneCanvas.Children.Add(m_RiverPathWater);
		}

		protected override void Disappear()
		{
			SceneCanvas.Children.Remove(m_RiverPathContour);
			//SceneCanvas.Children.Remove(m_RiverPathContour2);
			SceneCanvas.Children.Remove(m_RiverPathWater);
		}

		protected override Canvas SceneCanvas
		{
			get
			{
				return Scene.GetSceneObjectCanvas(MapSceneObjectLayers.AboveTerrain);
			}
		}

		private void CreateNewRiverPathData()
		{
			m_RiverPathData = new PathData();
			River.Content.Add(ContentNames.RiverPathData, m_RiverPathData);

			ExtendRiverPathData(true);
		}

		private void ExtendRiverPathData(bool isAddingToTail)
		{
			List<MapVertex> riverPts = River.Points;

			int oldCount = m_RiverPathData.Points.Count;
			int newCount = riverPts.Count;

			if (oldCount >= newCount)
				return;

			if (oldCount > 1)
			{
				if (isAddingToTail)
				{
					m_RiverPathData.Points[oldCount - 1] = CalculatePathPointLocation(oldCount - 1);
				}
				else
				{
					m_RiverPathData.Points[0] = CalculatePathPointLocation(newCount - oldCount);
				}
			}

			if (isAddingToTail)
			{
				for (int i = oldCount; i < newCount; i++)
					m_RiverPathData.Points.Add(CalculatePathPointLocation(i));
			}
			else
			{
				for (int i = newCount - oldCount - 1; i >= 0; i--)
					m_RiverPathData.Points.Insert(0, CalculatePathPointLocation(i));
			}
		}

		const double MAX_PATH_POINT_OFFSET = 1.5;

		private Point CalculatePathPointLocation(int index)
		{
			List<MapVertex> riverPts = River.Points;
			Point curPt = Scene.GetVertexPoint(riverPts[index]);

			if (index <= 0 || index >= riverPts.Count - 1)
				return curPt;

			MapVertex prevVert = riverPts[index - 1];
			MapVertex nextVert = riverPts[index + 1];

			Point prevPt = Scene.GetVertexPoint(prevVert);
			Point nextPt = Scene.GetVertexPoint(nextVert);

			Point midPt = prevPt + (nextPt - prevPt) / 2;

			double randAlpha = MathHelper.Rand.NextDouble() * MAX_PATH_POINT_OFFSET * 2 - MAX_PATH_POINT_OFFSET;

			return midPt + (curPt - midPt) / 2 * (1 + randAlpha);
		}

		private PathGeometry CreatePathGeo()
		{
			return CanonicalSplineHelper.CreateSpline(m_RiverPathData.Points, 0.5, null, false, false, 10/*Geometry.StandardFlatteningTolerance*/);
		}


		void River_Extended(object sender, RiverExtendedEventArgs e)
		{
			ExtendRiverPathData(e.IsExtendingTail);

			PathGeometry pathGeo = CreatePathGeo();

			m_RiverPathContour.Data = pathGeo;
			//m_RiverPathContour2.Data = pathGeo;
			m_RiverPathWater.Data = pathGeo;
		}

		private Path m_RiverPathContour;
		private Path m_RiverPathContour2;
		private Path m_RiverPathWater;
		private PathData m_RiverPathData;
	}
}
